﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GMC_4
{
    static class Disassembler
    {
        enum ValueType
        {
            OpCode,
            Constant,
            Subroutine
        }

        public static string ValueToLed(int value)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 6; i >= 0; --i)
            {
                if ((value & (1 << i)) == 0)
                    sb.Append('-');
                else
                    sb.Append('*');
            }
            return sb.ToString();
        }

        static string FormatAddress(int address)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(ValueToLed(address));
            sb.Append("  ");
            sb.Append(address.ToString("X2"));

            return sb.ToString();
        }

        private static string FormatLine(int address, byte value, ValueType valueType)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(FormatAddress(address));
            switch (valueType)
            {
                case ValueType.OpCode:
                    sb.AppendFormat("{0,6}  ", Ops.OpText[value]);
                    break;
                case ValueType.Constant:
                    sb.AppendFormat("   <{0:X}>  ", value);
                    break;
                case ValueType.Subroutine:
                    sb.AppendFormat("{0,6}  ", Ops.SubroutineText[value]);
                    break;
            }
            sb.Append(value.ToString("X"));
            return sb.ToString();
        }

        public static string[] Disassemble(IList<byte> ops)
        {
            List<string> output = new List<string>();

            int i = 0;
            while (i != ops.Count())
            {
                // check for uninitialized memory
                if (ops[i] == 0xf)
                {
                    if (i + 1 == ops.Count() || ops[i + 1] == 0xf)
                    {
                        while (i != ops.Count() && ops[i] == 0xf)
                            output.Add(FormatLine(i, ops[i++], ValueType.Constant));
                        continue;
                    }
                }

                byte op = ops[i];
                output.Add(FormatLine(i, ops[i], ValueType.OpCode));
                ++i;

                ValueType valueType = (op == (byte)OpCode.CAL) ? ValueType.Subroutine : ValueType.Constant;
                for (int j=0; i!=ops.Count() && j<Ops.ParamCounts[op]; ++j, ++i)
                    output.Add(FormatLine(i, ops[i], valueType));
            }

            return output.ToArray();
        }
    }
}
